package com.jakewharton.rxbinding4.component;

import static com.jakewharton.rxbinding4.internal.Preconditions.checkNotNull;

import com.jakewharton.rxbinding4.InitialValueObservable;
import com.jakewharton.rxbinding4.internal.Functions;

import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.functions.Predicate;
import ohos.agp.components.Text;
import ohos.agp.utils.Color;

/**
 * Static factory methods for creating {@linkplain Observable observables} and {@linkplain Consumer
 * actions}* for {@link Text}.
 */
public class RxText {
    /**
     * Create an observable of editor actions on {@code view}.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     * <p>
     * <em>Warning:</em> The created observable uses {@link Text.EditorActionListener} to
     * observe actions. Only one observable can be used for a view at a time.
     *
     * @param view view
     * @return the observable
     */
    @NonNull
    public static Observable<Integer> editorActions(@NonNull Text view) {
        checkNotNull(view, "view == null");
        return editorActions(view, Functions.PREDICATE_ALWAYS_TRUE);
    }

    /**
     * Create an observable of editor actions on {@code view}.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     * <p>
     * <em>Warning:</em> The created observable uses {@link Text.EditorActionListener} to
     * observe actions. Only one observable can be used for a view at a time.
     *
     * @param view    view
     * @param handled Predicate invoked each occurrence to determine the return value of the underlying {@link Text.EditorActionListener}.
     * @return the observable
     */
    @NonNull
    public static Observable<Integer> editorActions(@NonNull Text view, @NonNull Predicate<? super Integer> handled) {
        checkNotNull(view, "view == null");
        checkNotNull(handled, "handled == null");
        return new TextEditorActionObservable(view, handled);
    }

    /**
     * Create an observable of editor action events on {@code view}.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     * <p>
     * <em>Warning:</em> The created observable uses {@link Text.EditorActionListener} to
     * observe actions. Only one observable can be used for a view at a time.
     *
     * @param view view
     * @return the observable
     */
    @NonNull
    public static Observable<TextEditorActionEvent> editorActionEvents(@NonNull Text view) {
        checkNotNull(view, "view == null");
        return editorActionEvents(view, Functions.PREDICATE_ALWAYS_TRUE);
    }

    /**
     * Create an observable of editor action events on {@code view}.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     * <p>
     * <em>Warning:</em> The created observable uses {@link Text.EditorActionListener} to
     * observe actions. Only one observable can be used for a view at a time.
     *
     * @param view    view
     * @param handled Predicate invoked each occurrence to determine the return value of the underlying {@link Text.EditorActionListener}.
     * @return the observable
     */
    @NonNull
    public static Observable<TextEditorActionEvent> editorActionEvents(
            @NonNull Text view, @NonNull Predicate<? super TextEditorActionEvent> handled) {
        checkNotNull(view, "view == null");
        checkNotNull(handled, "handled == null");
        return new TextEditorActionEventObservable(view, handled);
    }

    /**
     * Create an observable of character sequences for text changes on {@code view}.
     * <p>
     * <em>Warning:</em> Values emitted by this observable are <b>mutable</b> and owned by the host
     * {@code Text} and thus are <b>not safe</b> to cache or delay reading (such as by observing
     * on a different thread). If you want to cache or delay reading the items emitted then you must
     * map values through a function which calls {@link String#valueOf} or
     * {@link CharSequence#toString() .toString()} to create a copy.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     * <p>
     * <em>Note:</em> A value will be emitted immediately on subscribe.
     *
     * @param view view
     * @return the initial value observable
     */
    @NonNull
    public static InitialValueObservable<CharSequence> textUpdates(@NonNull Text view) {
        checkNotNull(view, "view == null");
        return new TextTextUpdateObservable(view);
    }

    /**
     * Create an observable of text change events for {@code view}.
     * <p>
     * <em>Warning:</em> Values emitted by this observable contain a <b>mutable</b>
     * {@link CharSequence} owned by the host {@code Text} and thus are <b>not safe</b> to cache
     * or delay reading (such as by observing on a different thread). If you want to cache or delay
     * reading the items emitted then you must map values through a function which calls
     * {@link String#valueOf} or {@link CharSequence#toString() .toString()} to create a copy.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     * <p>
     * <em>Note:</em> A value will be emitted immediately on subscribe.
     *
     * @param view view
     * @return the initial value observable
     */
    @NonNull
    public static InitialValueObservable<TextTextUpdateEvent> textUpdateEvents(@NonNull Text view) {
        checkNotNull(view, "view == null");
        return new TextTextUpdateEventObservable(view);
    }


    /**
     * An action which sets the text property of {@code view} with character sequences.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     *
     * @param view view
     * @return the consumer
     * @deprecated Use view::setText method reference.
     */
    @Deprecated
    @NonNull
    public static Consumer<? super String> text(@NonNull Text view) {
        checkNotNull(view, "view == null");
        return view::setText;
    }

    /**
     * An action which sets the text property of {@code view} string resource IDs.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     *
     * @param view view
     * @return the consumer
     * @deprecated Use view::setText method reference.
     */
    @Deprecated
    @NonNull
    public static Consumer<? super Integer> textRes(@NonNull Text view) {
        checkNotNull(view, "view == null");
        return view::setText;
    }

    /**
     * An action which sets the hint property of {@code view} with character sequences.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     *
     * @param view view
     * @return the consumer
     * @deprecated Use view::setHint method reference.
     */
    @Deprecated
    @NonNull
    public static Consumer<? super String> hint(@NonNull Text view) {
        checkNotNull(view, "view == null");
        return view::setHint;
    }

    /**
     * An action which sets the color property of {@code view} with color integer.
     * <p>
     * <em>Warning:</em> The created observable keeps a strong reference to {@code view}. Unsubscribe
     * to free this reference.
     *
     * @param view view
     * @return the consumer
     * @deprecated Use view::setTextColor method reference.
     */
    @Deprecated
    @NonNull
    public static Consumer<? super Color> color(@NonNull Text view) {
        checkNotNull(view, "view == null");
        return view::setTextColor;
    }

    private RxText() {
        throw new AssertionError("No instances.");
    }
}
